package com.bpmn.flow.listener;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONUtil;
import com.bpmn.api.BpmTaskCallbackReqDTO;
import com.bpmn.flow.cmd.TimeoutCmd;
import com.bpmn.flow.controller.form.ModelMetaInfoForm;
import com.bpmn.utils.QueryUtils;
import lombok.extern.slf4j.Slf4j;
import org.flowable.common.engine.api.delegate.event.FlowableEngineEntityEvent;
import org.flowable.common.engine.api.delegate.event.FlowableEngineEventType;
import org.flowable.engine.ManagementService;
import org.flowable.engine.delegate.event.AbstractFlowableEngineEventListener;
import org.flowable.engine.delegate.event.FlowableActivityCancelledEvent;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.engine.repository.Model;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.Set;

/**
 * 监听 {@link Task} 的开始与完成
 *
 * @author rain
 */
@Component
@Slf4j
public class BpmTaskEventListener extends AbstractFlowableEngineEventListener {

    @Value("${flowable.async-executor-activate}")
    private boolean asyncExecutorActivate;

    public static final Set<FlowableEngineEventType> TASK_EVENTS =
            Set.of(FlowableEngineEventType.TASK_CREATED, FlowableEngineEventType.TASK_ASSIGNED,
                    FlowableEngineEventType.TASK_COMPLETED, FlowableEngineEventType.ACTIVITY_CANCELLED,
                    FlowableEngineEventType.TIMER_FIRED);

    public BpmTaskEventListener() {
        super(TASK_EVENTS);
    }

    @Override
    protected void taskCreated(FlowableEngineEntityEvent event) {
        Task task = (Task) event.getEntity();
        //超时自动审批功能
        if (asyncExecutorActivate && task.getDueDate() != null && task.getDueDate().after(new Date())) {
            ManagementService managementService = CommandContextUtil.getProcessEngineConfiguration().getManagementService();
            managementService.executeCommand(new TimeoutCmd(task.getProcessInstanceId(), task.getId(), task.getDueDate()));
        }
    }

    @Override
    protected void taskAssigned(FlowableEngineEntityEvent event) {
        //TODO
    }

    @Override
    protected void taskCompleted(FlowableEngineEntityEvent event) {
        //处理回调逻辑
        Task task = (Task) event.getEntity();
        ProcessDefinition processDefinition = QueryUtils.definitionQuery().processDefinitionId(task.getProcessDefinitionId()).singleResult();
        Model model = QueryUtils.modelQuery().deploymentId(processDefinition.getDeploymentId()).singleResult();
        ModelMetaInfoForm metaInfo = JSONUtil.toBean(model.getMetaInfo(), ModelMetaInfoForm.class);
        String taskCallbackUrl = metaInfo.getTaskCallbackUrl();
        ProcessInstance processInstance = QueryUtils.instanceQuery(task.getProcessInstanceId()).singleResult();
        if (StrUtil.isNotBlank(taskCallbackUrl)) {
            //构造回调请求参数
            BpmTaskCallbackReqDTO taskCallbackReqDTO = new BpmTaskCallbackReqDTO();
            taskCallbackReqDTO.setTaskId(task.getId());
            taskCallbackReqDTO.setTaskName(task.getName());
            taskCallbackReqDTO.setTaskDefinitionKey(task.getTaskDefinitionKey());
            taskCallbackReqDTO.setEventName(event.getType().name());
            taskCallbackReqDTO.setProcessInstanceId(task.getProcessInstanceId());
            taskCallbackReqDTO.setProcessDefinitionKey(processInstance.getProcessDefinitionKey());
            taskCallbackReqDTO.setBusinessKey(processInstance.getBusinessKey());
            taskCallbackReqDTO.setStartUserName(processInstance.getStartUserId());
            String jsonStr = JSONUtil.toJsonStr(taskCallbackReqDTO);
            try (HttpResponse response = HttpRequest.post(taskCallbackUrl).body(jsonStr).execute()) {
                log.info("处理回调成功: {}", response.body());
            } catch (Exception e) {
                log.error("处理回调失败", e);
            }
        }
    }

    @Override
    protected void activityCancelled(FlowableActivityCancelledEvent event) {
        //TODO
    }

    @Override
    protected void timerFired(FlowableEngineEntityEvent event) {
        //TODO
    }

}
